// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: simplify xml profile
// ------------------------------------------------------------------

#ifndef XMLPARSER_XMLTREE_H_
#define XMLPARSER_XMLTREE_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

namespace vbsutil {
namespace xmlparser {

enum class NodeType {
    PROFILES,
    PARTICIPANT,
    PUBLISHER,
    SUBSCRIBER,
    RTPS,
    QOS_PROFILE,
    APPLICATION,
    TYPE,
    TOPIC,
    DATA_WRITER,
    DATA_READER,
    DDS,
    TYPES,
    LOG,
    LIBRARY_SETTINGS,
    VBS
};

class BaseNode {
 public:
    BaseNode(const NodeType type) : data_type_(type), parent_(nullptr) {}

    virtual ~BaseNode() = default;

    BaseNode(const BaseNode&) = delete;
    BaseNode& operator=(const BaseNode&) = delete;

    BaseNode(BaseNode&&) = default;
    BaseNode& operator=(BaseNode&&) = default;

    NodeType getType() const { return data_type_; }

    void addChild(std::unique_ptr<BaseNode> child) {
        child->setParent(this);
        children.push_back(std::move(child));
    }

    bool removeChild(const size_t& index) {
        if (children.size() > index) {
            (void)children.erase(children.begin() + index);
            return true;
        } else {
            return false;
        }
    }

    BaseNode* getChild(const size_t& index) const {
        if (children.empty() || (index >= children.size())) {
            return nullptr;
        }
        return children[index].get();
    }
    BaseNode* getParent() const { return parent_; }

    void setParent(BaseNode* const parent) { parent_ = parent; }
    size_t getNumChildren() const { return children.size(); }

    std::vector<std::unique_ptr<BaseNode>>& getChildren() { return children; }

 private:
    NodeType data_type_;
    BaseNode* parent_;
    std::vector<std::unique_ptr<BaseNode>> children;
};

template <class T>
class DataNode : public BaseNode {
 public:
    DataNode(NodeType ntype);
    DataNode(const NodeType ntype, std::unique_ptr<T> data);
    virtual ~DataNode();

    DataNode(const DataNode&) = delete;
    DataNode& operator=(const DataNode&) = delete;

    T* get() const;
    std::unique_ptr<T> getData();
    void setData(std::unique_ptr<T> data);

    void addAttribute(const std::string& name, const std::string& value);
    const std::map<std::string, std::string>& getAttributes() const;

 private:
    std::map<std::string, std::string> attributes_;
    std::unique_ptr<T> data_;
};

template <class T>
DataNode<T>::DataNode(NodeType ntype) : BaseNode(ntype), attributes_(), data_(nullptr) {}

template <class T>
DataNode<T>::DataNode(const NodeType ntype, std::unique_ptr<T> data)
    : BaseNode(ntype), attributes_(), data_(std::move(data)) {}

template <class T>
DataNode<T>::~DataNode() {}
template <class T>
T* DataNode<T>::get() const {
    return data_.get();
}

template <class T>
std::unique_ptr<T> DataNode<T>::getData() {
    return std::move(data_);
}

template <class T>
void DataNode<T>::setData(std::unique_ptr<T> data) {
    data_ = std::move(data);
}

template <class T>
void DataNode<T>::addAttribute(const std::string& name, const std::string& value) {
    attributes_[name] = value;
}

template <class T>
const std::map<std::string, std::string>& DataNode<T>::getAttributes() const {
    return attributes_;
}

}  // namespace xmlparser
}  // namespace vbsutil
#endif  // INCLUDE_ERTPS_XMLPARSER_XMLTREE_H_
